package com.sl.core.engine.scripts;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sl.core.utils.JsonUtil;
import org.apache.hop.core.logging.ILogChannel;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;

/**
 * @Description: TODO
 * @Version: 1.0.0
 */
public class GroovyCondition {

    private List<GroovyRule> list;

    public GroovyCondition(List<GroovyRule> list) {
        this.list = list;
    }

    public void addRule(GroovyRule groovyRule) {
        if (ObjectUtil.isNull(list)) {
            list = Lists.newArrayList();
        }
        list.add(groovyRule);
    }

    public void addRule(List<GroovyRule> groovyRuleList) {
        if (ObjectUtil.isNull(list)) {
            list = Lists.newArrayList();
        }
        list.addAll(groovyRuleList);

    }


    public boolean evaluate(Map<String, Object> params, ILogChannel logChannel) {

        if (CollUtil.isEmpty(list)) {
            return false;
        }
        Map<String, Object> convert = Maps.newHashMap();
        convert.putAll(params);

        String s = wrapperScripts(convert, logChannel);
        logChannel.logDebug("生成的规则校验脚本:" + s);
        Object o = GroovyScriptExecutor.INSTANCE.executeScript(s, convert);
        if (ObjectUtil.isNull(o)) {
            return false;
        }
        if (logChannel.isDebug()) {
            logChannel.logDebug("执行参数【" + JsonUtil.toStr(convert) + "】,执行结果【" + JsonUtil.toStr(o) + "】");
        }
        return Convert.toBool(o);
    }

    public String wrapperScripts(Map<String, Object> convert, ILogChannel logChannel) {
        String s = buildScript(convert, logChannel);
        return "import " + this.getClass().getName() + ";\n /**\n" + "* input: 原始输入变量\n" + "* output: 经过手工码转换后的输出变量【注：建议 return output】\n" + "*/\n" + "def main(Map input){\n" + "\t\n" + "if(" + s + "){\n return true;\n }\n else{\n return false;\n }" + "}\n";

    }

    public String buildViewScript(Map<String, Object> convert, ILogChannel logChannel) {

        StringBuilder stringBuilder = new StringBuilder();
        Integer i = 0;
        for (GroovyRule groovyRule : list) {
            StringJoiner stringJoiner = new StringJoiner("");
            String symbol = groovyRule.getLeftSymbol();
            if (StrUtil.isNotBlank(symbol)) {
                stringJoiner.add(symbol);
            }

            String relation = groovyRule.getRelation();
            if (StrUtil.isNotBlank(relation)) {
                if (StrUtil.equalsIgnoreCase(relation, "and")) {
                    stringJoiner.add(" && ");
                } else if (StrUtil.equalsIgnoreCase(relation, "or")) {
                    stringJoiner.add(" || ");
                } else {
                    if (ObjectUtil.isNotNull(logChannel)) {
                        logChannel.logError(relation + "字段不能识别！");
                    }
                }
            }

            String leftValueName = groovyRule.getLeftValueName();
            if (StrUtil.isNotBlank(leftValueName)) {
                stringJoiner.add(leftValueName);
            }

            String function = groovyRule.getFunction();

            if (StrUtil.isNotBlank(function)) {
                stringJoiner.add(" "+function+" ");
            }

            Object rightValue = groovyRule.getRightValue();
            if(ObjectUtil.isNotNull(rightValue)){
                stringJoiner.add(rightValue.toString());

            }


            String rightSymbol = groovyRule.getRightSymbol();
            if (StrUtil.isNotBlank(rightSymbol)) {
                stringJoiner.add(rightSymbol);
            }

            stringBuilder.append(stringJoiner);
            i++;
        }

        return stringBuilder.toString();
    }

    public String buildScript(Map<String, Object> convert, ILogChannel logChannel) {

        StringBuilder stringBuilder = new StringBuilder();
        Integer i = 0;
        for (GroovyRule groovyRule : list) {
            String str = "";
            String symbol = groovyRule.getLeftSymbol();
            if (StrUtil.isNotBlank(symbol)) {
                str += symbol;
            }

            String leftValueName = groovyRule.getLeftValueName();
            if (StrUtil.isNotBlank(leftValueName)) {
                leftValueName = "input['" + leftValueName + "']";
            }

            String rightValueName = groovyRule.getRightValueName();
            Object rightValue = groovyRule.getRightValue();

            if (ObjectUtil.isNotNull(rightValue)) {
                convert.put("$" + i, rightValue);
                rightValueName = "$" + i;
            }

            if (StrUtil.isNotBlank(rightValueName)) {
                rightValueName = " input['" + rightValueName + "']";
            }

            String function = groovyRule.getFunction();

            if (StrUtil.isNotBlank(function)) {
                function = buildFunction(function, leftValueName, rightValueName);
                str += "" + function;
            }


            String relation = groovyRule.getRelation();
            if (StrUtil.isNotBlank(relation)) {
                if (StrUtil.equalsIgnoreCase(relation, "and")) {
                    str += " && \n ";
                } else if (StrUtil.equalsIgnoreCase(relation, "or")) {
                    str += " || \n ";
                } else {
                    if (ObjectUtil.isNotNull(logChannel)) {
                        logChannel.logError(relation + "字段不能识别！");
                    }
                }
            }
            String rightSymbol = groovyRule.getRightSymbol();
            if(StrUtil.equals(rightSymbol,"right")){
                rightSymbol=StrUtil.EMPTY;
            }
            if (StrUtil.isNotBlank(rightSymbol)) {
                str += rightSymbol;
            }

            stringBuilder.append(str);
            i++;
        }

        return stringBuilder.toString();

    }

    private String buildFunction(String sourceFunc, String leftValueName, String rightValueName) {
        String targetFunc = "";
        switch (sourceFunc) {
            case "=":
                targetFunc = "GroovyCondition.equal(" + leftValueName + "," + rightValueName + ")";
                break;
            case "<>":
                targetFunc = "GroovyCondition.notEqual(" + leftValueName + "," + rightValueName + ")";
                break;
            case "<":
                targetFunc = "GroovyCondition.lt(" + leftValueName + "," + rightValueName + ")";
                break;
            case "<=":
                targetFunc = "GroovyCondition.ltEq(" + leftValueName + "," + rightValueName + ")";
                break;
            case ">":
                targetFunc = "GroovyCondition.gt(" + leftValueName + "," + rightValueName + ")";
                break;
            case ">=":
                targetFunc = "GroovyCondition.gtEq(" + leftValueName + "," + rightValueName + ")";
                break;
            case "IS NULL":
                targetFunc = "GroovyCondition.isNull(" + leftValueName + ")";
                break;
            case "IS NOT NULL":
                targetFunc = "GroovyCondition.isNotNull(" + leftValueName + ")";
                break;
            case "IS EMPTY":
                targetFunc = "GroovyCondition.isEmpty(" + leftValueName + ")";
                break;
            case "IS NOT EMPTY":
                targetFunc = "GroovyCondition.isNotEmpty(" + leftValueName + ")";
                break;
            case "RIGHT LIKE":
                targetFunc = "GroovyCondition.endWith(" + leftValueName + "," + rightValueName + ")";
                break;
            case "LEFT LIKE":
                targetFunc = "GroovyCondition.startWith(" + leftValueName + "," + rightValueName + ")";
                break;
            case "ALL LIKE":
                targetFunc = "GroovyCondition.contains(" + leftValueName + "," + rightValueName + ")";
                break;
            case "LIKE":
                targetFunc = "GroovyCondition.contains(" + leftValueName + "," + rightValueName + ")";
                break;
        }
        return targetFunc;
    }

    public static boolean notEqual(Object o1, Object o2) {
        return !equal(o1, o2);
    }

    public static boolean equal(Object o1, Object o2) {
        if (ObjectUtil.isNull(o1)) {
            return false;
        }

        if (ObjectUtil.isNull(o2)) {
            return false;
        }
        //如果是整型数字转字符串比较
        if (o1 instanceof Long) {
            o1 = o1.toString();
        }
        //如果是整型数字转字符串比较
        if (o1 instanceof Integer) {
            o1 = o1.toString();
        }

        //如果是整型数字转字符串比较
        if (o2 instanceof Long) {
            o2 = o2.toString();
        }
        //如果是整型数字转字符串比较
        if (o2 instanceof Integer) {
            o2 = o2.toString();
        }
        return ObjectUtil.equal(o1, o2);
    }

    /**
     * 小于
     *
     * @param o1
     * @return
     */
    public static boolean lt(Object o1, Object o2) {
        if (ObjectUtil.isNull(o1)) {
            return false;
        }

        if (ObjectUtil.isNull(o2)) {
            return false;
        }
        BigDecimal big1 = Convert.toBigDecimal(o1);
        if (ObjectUtil.isNull(big1)) {
            return false;
        }
        BigDecimal big2 = Convert.toBigDecimal(o2);
        if (ObjectUtil.isNull(big2)) {
            return false;
        }
        return big1.compareTo(big2) < 0;
    }

    /**
     * 小于等于
     *
     * @param o1
     * @return
     */
    public static boolean ltEq(Object o1, Object o2) {
        if (ObjectUtil.isNull(o1)) {
            return false;
        }

        if (ObjectUtil.isNull(o2)) {
            return false;
        }
        BigDecimal big1 = Convert.toBigDecimal(o1);
        if (ObjectUtil.isNull(big1)) {
            return false;
        }
        BigDecimal big2 = Convert.toBigDecimal(o2);
        if (ObjectUtil.isNull(big2)) {
            return false;
        }
        return big1.compareTo(big2) <= 0;
    }

    /**
     * 大于
     *
     * @param o1
     * @return
     */
    public static boolean gt(Object o1, Object o2) {
        if (ObjectUtil.isNull(o1)) {
            return false;
        }

        if (ObjectUtil.isNull(o2)) {
            return false;
        }
        BigDecimal big1 = Convert.toBigDecimal(o1);
        if (ObjectUtil.isNull(big1)) {
            return false;
        }
        BigDecimal big2 = Convert.toBigDecimal(o2);
        if (ObjectUtil.isNull(big2)) {
            return false;
        }
        return big1.compareTo(big2) > 0;
    }

    /**
     * 大于等于
     *
     * @param o1
     * @return
     */
    public static boolean gtEq(Object o1, Object o2) {
        if (ObjectUtil.isNull(o1)) {
            return false;
        }

        if (ObjectUtil.isNull(o2)) {
            return false;
        }
        BigDecimal big1 = Convert.toBigDecimal(o1);
        if (ObjectUtil.isNull(big1)) {
            return false;
        }
        BigDecimal big2 = Convert.toBigDecimal(o2);
        if (ObjectUtil.isNull(big2)) {
            return false;
        }
        return big1.compareTo(big2) >= 0;
    }

    public static boolean isNull(Object o1) {
        return ObjectUtil.isNull(o1);
    }

    public static boolean isNotNull(Object o1) {
        return ObjectUtil.isNotNull(o1);
    }

    public static boolean isEmpty(Object o1) {
        return ObjectUtil.isEmpty(o1);
    }

    public static boolean isNotEmpty(Object o1) {
        return ObjectUtil.isNotEmpty(o1);
    }

    public static boolean endWith(Object o1, Object o2) {
        if (ObjectUtil.isNull(o1)) {
            return false;
        }

        if (ObjectUtil.isNull(o2)) {
            return false;
        }
        String str1 = o1.toString();
        String str2 = o2.toString();
        return StrUtil.endWithIgnoreCase(str1, str2);
    }

    public static boolean startWith(Object o1, Object o2) {
        if (ObjectUtil.isNull(o1)) {
            return false;
        }

        if (ObjectUtil.isNull(o2)) {
            return false;
        }
        String str1 = o1.toString();
        String str2 = o2.toString();
        return StrUtil.startWithIgnoreCase(str1, str2);
    }

    public static boolean contains(Object o1, Object o2) {
        if (ObjectUtil.isNull(o1)) {
            return false;
        }

        if (ObjectUtil.isNull(o2)) {
            return false;
        }
        String str1 = o1.toString();
        String str2 = o2.toString();
        return StrUtil.containsIgnoreCase(str1, str2);
    }

}
